package admin

import (
	j_log "config-client-v1/init/j-log"
	"config-client-v1/model"
	"config-client-v1/utils/tools"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/gorilla/websocket"
	"gorm.io/gorm"
	"time"
)

type PPEController struct {
}

func (con PPEController) List(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		ProtocolName string `json:"protocol_name"`
		Name         string `json:"name"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	tx := model.DB.Where("project_id = ?", userToken.ProjectID)
	if param.Name != "" {
		tx.Where("name = ?", param.Name)
	}
	if param.ProtocolName != "" {
		tx.Where("protocol_name = ?", param.ProtocolName)
	}
	var count int64
	list := make([]model.PPE, 0)
	err = tx.Model(&model.PPE{}).Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = tx.Order("id desc").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

func (con PPEController) Save(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		Id           int    `json:"id"`
		ProtocolName string `json:"protocol_name" binding:"required,max=30"`
		Name         string `json:"name" binding:"required,max=30"`
		Config       string `json:"config" binding:"required"`
	}{}

	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	now := tools.GetNow()
	data := &model.PPE{}
	data.ID = param.Id
	data.ProjectID = userToken.ProjectID
	data.ProtocolName = param.ProtocolName
	data.Name = param.Name
	data.Config = param.Config
	err = data.ValidatePPE()
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": err.Error(),
		})
		return
	}

	if param.Id == 0 {
		usedCode2 := make([]string, 0)
		//if data.ProtocolName == "OPC Client" {
		//	err = model.DB.Model(&model.PPE{}).Where("project_id = ? AND code1 = ? AND code3 = ?", userToken.ProjectID, data.Code1, data.Code3).Pluck("code2", &usedCode2).Error
		//} else {
		//  err = model.DB.Model(&model.PPE{}).Where("project_id = ? AND code1 = ?", userToken.ProjectID, data.Code1).Pluck("code2", &usedCode2).Error
		//}
		err = model.DB.Model(&model.PPE{}).Where("project_id = ? AND code1 = ?", userToken.ProjectID, data.Code1).Pluck("code2", &usedCode2).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		availableCode2 := model.GetAvailableCode(model.AllCode2(), usedCode2)
		if len(availableCode2) == 0 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "当前通讯模块序号已满 code2",
			})
			return
		}

		data.Code2 = availableCode2[0]
		data.RunningState = 4
		data.CreateTime = &now
		data.UpdateTime = &now
		err = model.DB.Omit("FrameList").Create(data).Error
	} else {
		ppeOld := &model.PPE{}
		exist, err2 := ppeOld.Exists(param.Id)
		if !exist {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的 ppe_id",
				"data": map[string]interface{}{
					"err": err2,
				},
			})
			return
		}
		if ppeOld.ProtocolName != param.ProtocolName {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "协议不可修改",
			})
			return
		}
		if ppeOld.Mode != data.Mode {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "协议模式不可修改",
			})
			return
		}
		data.UpdateTime = &now
		err = model.DB.Model(&model.PPE{}).Omit("FrameList").Where("id = ?", param.Id).Select("name", "config", "detail", "update_time").Updates(data).Error
	}
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con PPEController) Detail(ctx *gin.Context) {
	param := struct {
		Id int `json:"id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	info := model.PPE{}

	err = model.DB.Model(&model.PPE{}).Preload("FrameList", func(db *gorm.DB) *gorm.DB {
		return db.Where("del = 0").Order("id DESC")
	}).Where("id = ?", param.Id).First(&info).Error

	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"info": info,
		},
	})
}

func (con PPEController) Delete(ctx *gin.Context) {
	param := struct {
		Id int `json:"id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	info := model.PPE{}
	err = model.DB.Model(&model.PPE{}).Where("id = ?", param.Id).First(&info).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	err = model.DB.Transaction(func(tx *gorm.DB) error {
		err = tx.Where("id = ?", param.Id).Delete(&model.PPE{}).Error
		if err != nil {
			return err
		}
		err = tx.Where("ppe_id = ?", param.Id).Delete(&model.Frame{}).Error
		if err != nil {
			return err
		}
		err = tx.Where("ppe_id = ?", param.Id).Delete(&model.FrameItem{}).Error
		if err != nil {
			return err
		}
		err = tx.Where("ppe_id = ?", param.Id).Delete(&model.ModbusServerDB{}).Error
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    10,
			"message": err.Error(),
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con PPEController) PPEStart(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		PPEID int `json:"ppe_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	ppeExist, ok := model.RunningPPEMap.Get(param.PPEID)
	if ok && ppeExist.RunningState != 4 {
		j_log.LogError([]interface{}{ppeExist.Name, "协议运行中, 不可重复运行", ppeExist.ProtocolName})
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "当前通讯协议已运行",
		})
		return
	}

	ppe := &model.PPE{}
	err = model.DB.Preload("FrameList").Preload("ModbusServerDB").Where("id = ? AND project_id = ? AND del = 0", param.PPEID, userToken.ProjectID).Limit(1).Find(ppe).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	if ppe.ID == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的 ppe_id",
		})
		return
	}
	if ppe.RunningState == 2 {
		ppe.RunningState = 4
	}
	if model.RunningProject.ID != 0 && ppe.ProjectID != model.RunningProject.ID {
		j_log.LogError([]interface{}{ppe.Name, "只能运行一个工程", ppe.ProjectID})
		ctx.JSON(200, gin.H{
			"code":    10,
			"message": "只能运行一个工程",
			"data": map[string]interface{}{
				"running_project_id": model.RunningProject.ID,
				"current_project_id": ppe.ProjectID,
			},
		})
		return
	}
	for _, frame := range ppe.FrameList {
		frame.JsonDetail, _ = model.GetLatestFrameJsonDetail(frame)
	}
	err = model.ProjectStartHook(ppe.ProjectID)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": err.Error(),
		})
		return
	}
	err = ppe.UpdateVariablesMap()
	if err != nil {
		j_log.LogError([]interface{}{"ppe更新变量map失败", ppe.Name})
	}
	err = ppe.Start()
	time.Sleep(time.Millisecond * 500)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": err.Error(),
		})
		_ = model.SysAlertSave(&model.SysAlert{
			ProjectID:  ppe.ProjectID,
			Const:      model.ProtocolAlertConst[ppe.ProtocolName],
			Alert:      ppe.ProtocolName + "设备启动超时",
			RelationID: ppe.ID,
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"running_state": 2,
		},
	})
}

func (con PPEController) PPEStop(ctx *gin.Context) {
	param := struct {
		PPEID int `json:"ppe_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	ppe, ok := model.RunningPPEMap.Get(param.PPEID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "当前ppe_id通讯协议未运行",
		})
		return
	}
	err = ppe.Stop()
	time.Sleep(time.Millisecond * 500)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": err.Error(),
		})
		return
	}
	//_ = ppe.UpdateRunningState(4, "")
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"running_state": 4,
		},
	})
}

func (con PPEController) PPEStatus(ctx *gin.Context) {
	param := struct {
		PPEID int `json:"ppe_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	ppe, ok := model.RunningPPEMap.Get(param.PPEID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "当前ppe_id通讯协议未运行",
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"info": ppe,
		},
	})
}

func (con PPEController) OPCVariableAdd(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		PPEID     int    `json:"ppe_id" binding:"required"`            // ppe_id
		FieldName string `json:"field_name" binding:"required,max=20"` // 变量名称
		OPCAddr   string `json:"opc_addr" binding:"required,max=255"`  // OPC 变量地址
		SpecType  string `json:"spec_type" binding:"max=20"`           // 数据类型 [uint8,int8,uint16....bool]
	}{}

	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	ppe := &model.PPE{}
	exist, err := ppe.Exists(param.PPEID)
	if !exist {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的 ppe_id",
			"data":    err,
		})
		return
	}
	if ppe.ProtocolName != "OPC Client" && ppe.ProtocolName != "OPC DA Client" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "当前设备不是OPC Client通讯协议",
		})
		return
	}
	now := tools.GetNow()
	data := &model.FrameItem{}
	data.ProjectID = userToken.ProjectID
	data.PPEID = param.PPEID
	data.FieldName = param.FieldName
	data.OPCAddr = param.OPCAddr
	data.SpecType = param.SpecType
	data.Code1 = ppe.Code1
	data.Code2 = ppe.Code2
	data.Code3 = ppe.Code3

	frameItemExist := &model.FrameItem{}
	err = model.DB.Where("ppe_id = ? AND opc_addr = ?", param.PPEID, param.OPCAddr).Limit(1).Find(&frameItemExist).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	if frameItemExist.ID != 0 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "当前OPC设备下的变量地址重复",
		})
		return
	}

	switch data.SpecType {
	case "bool":
	case "uint8":
	case "uint16":
	case "uint32":
	case "int8":
	case "int16":
	case "int32":
	case "float32":
	default:
		err = errors.New(fmt.Sprintf("暂不支持数据类型%s", data.SpecType))
		return
	}

	usedCode4 := make([]string, 0)
	err = model.DB.Model(&model.FrameItem{}).Where("project_id = ? AND code1 = ? AND code2 = ? AND code3 = ?", userToken.ProjectID, data.Code1, data.Code2, data.Code3).Pluck("code4", &usedCode4).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	availableCode4 := model.GetAvailableCode(model.AllCode4(), usedCode4)
	if len(availableCode4) < 1 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "当前OPC设备下的变量地址已满",
		})
		return
	}

	data.Code4 = availableCode4[0]
	data.Addr = fmt.Sprintf("%s-%s-%s-%s", data.Code1, data.Code2, data.Code3, data.Code4)
	data.RatioOperator = "*"
	data.Ratio = 1
	data.CreateTime = &now
	data.UpdateTime = &now
	err = model.DB.Create(data).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con PPEController) OPCPointAdd(ctx *gin.Context) {
	param := struct {
		ID    int    `json:"id"`
		PPEID int    `json:"ppe_id" binding:"required"`        // ppe_id
		Tag   string `json:"tag" binding:"required,max=255"`   // 变量标签(名称)
		PAddr string `json:"paddr" binding:"required,max=255"` // OPC变量地址
	}{}

	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	ppe := &model.PPE{}
	exist, err := ppe.Exists(param.PPEID)
	if !exist {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的 ppe_id",
			"data":    err,
		})
		return
	}
	if ppe.ProtocolName != "OPC Server" && ppe.ProtocolName != "OPC DA Server" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "当前设备不是OPC Server通讯协议",
		})
		return
	}
	data := &model.OPCServerItem{}
	data.ProjectID = ppe.ProjectID
	data.PPEID = param.PPEID
	data.Tag = param.Tag
	data.PAddr = param.PAddr
	if param.ID == 0 {
		frameItemExist := &model.OPCServerItem{}
		err = model.DB.Where("ppe_id = ? AND tag = ?", param.PPEID, param.Tag).Limit(1).Find(&frameItemExist).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		if frameItemExist.ID != 0 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "当前OPC设备下的tag重复",
			})
			return
		}
		err = model.DB.Create(data).Error
	} else {
		frameItemExist := &model.OPCServerItem{}
		err = model.DB.Where("id != ? AND ppe_id = ? AND tag = ?", param.ID, param.PPEID, param.Tag).Limit(1).Find(&frameItemExist).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		if frameItemExist.ID != 0 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "当前OPC设备下的tag重复",
			})
			return
		}
		err = model.DB.Model(&model.OPCServerItem{}).Where("id = ?", param.ID).Select("paddr", "tag").Updates(data).Error
	}

	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con PPEController) OPCPointList(ctx *gin.Context) {
	param := struct {
		Tag   string `json:"tag"`
		PPEID int    `json:"ppe_id"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	tx := model.DB.Model(&model.OPCServerItem{})
	if param.PPEID != 0 {
		tx.Where("ppe_id = ?", param.PPEID)
	}
	if param.Tag != "" {
		tx.Where("tag = ?", param.Tag)
	}
	var count int64
	list := make([]*model.OPCServerItem, 0)
	err = tx.Model(&model.OPCServerItem{}).Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = tx.Order("id desc").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

func (con PPEController) OPCPointDelete(ctx *gin.Context) {
	param := struct {
		Id int `json:"id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	info := model.OPCServerItem{}
	err = model.DB.Model(&model.OPCServerItem{}).Where("id = ?", param.Id).First(&info).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = model.DB.Where("id = ?", param.Id).Delete(&model.OPCServerItem{}).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con PPEController) OPCReadNodes(ctx *gin.Context) {
	param := struct {
		PPEID int `json:"ppe_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	ppe, ok := model.RunningPPEMap.Get(param.PPEID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "当前ppe_id通讯协议未运行",
		})
		return
	}
	if ppe.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "设备未运行 " + ppe.Detail,
			"data":    map[string]interface{}{},
		})
		return
	}

	jsonB := make([]byte, 0)
	if ppe.ProtocolName == "OPC Client" {
		req := model.OPCWSRequest{
			Route: "opcua/readnodes",
			TS:    tools.GetNow(),
			Params: map[string]interface{}{
				"ppe_id": param.PPEID,
			},
		}
		jsonB, _ = json.Marshal(&req)
	} else if ppe.ProtocolName == "OPC DA Client" {
		req := model.OPCWSRequest{
			Route: "opcda/readnodes",
			TS:    tools.GetNow(),
			Params: map[string]interface{}{
				"ppe_id": param.PPEID,
			},
		}
		jsonB, _ = json.Marshal(&req)
	} else {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "当前设备不是OPC Client通讯协议",
		})
		return
	}

	rawData := string(jsonB)
	if model.OPCWSClient == nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": fmt.Sprintf("OPCWSClient 未连接"),
			"data": map[string]interface{}{
				"rawData": rawData,
			},
		})
		return
	}
	err = model.OPCWSClient.WriteMessage(websocket.TextMessage, jsonB)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": fmt.Sprintf("OPCWSClient.WriteMessage error %s", err.Error()),
			"rawData": rawData,
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"rawData": rawData,
		},
	})
}

func (con PPEController) OPCNodesList(ctx *gin.Context) {
	param := struct {
		PPEID  int    `json:"ppe_id"`
		NodeId string `json:"NodeId"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	tx := model.DB.Model(&model.OPCNodes{})
	if param.PPEID != 0 {
		tx.Where("ppe_id = ?", param.PPEID)
	}
	if param.NodeId != "" {
		tx.Where("NodeId like ?", "%"+param.NodeId+"%")
	}
	var count int64
	list := make([]*model.OPCNodes, 0)
	err = tx.Model(&model.OPCNodes{}).Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = tx.Order("id desc").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

func (con PPEController) OPCNodesHandle(ctx *gin.Context) {
	param := struct {
		IDS    string `json:"ids"`
		Status uint8  `json:"status" binding:"required"` // [2.覆盖 3.忽略]
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	if param.Status != 2 {
		param.Status = 3
	}

	list := make([]*model.OPCNodes, 0)
	if param.IDS == "" {
		err = model.DB.Where("status=1").Find(&list).Error
	} else {
		ids := tools.StrToIntSlice(param.IDS)
		if len(ids) == 0 {
			ctx.JSON(200, gin.H{
				"code":    0,
				"message": "success",
				"data":    "",
			})
			return
		}
		err = model.DB.Where("id in ? AND status=1", ids).Find(&list).Error
	}
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	/*--- 获取PPEMap start ---*/
	ppeIDS := make([]int, 0)
	ppeIDSMap := make(map[int]bool)
	for _, node := range list {
		ppeIDSMap[node.PPEID] = true
	}
	for ppeID := range ppeIDSMap {
		ppeIDS = append(ppeIDS, ppeID)
	}
	ppeList := make([]*model.PPE, 0)
	err = model.DB.Where("id in ?", ppeIDS).Find(&ppeList).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ppeMap := make(map[int]*model.PPE)
	for _, ppe := range ppeList {
		ppeMap[ppe.ID] = ppe
	}
	/*--- 获取PPEMap end ---*/

	now := tools.GetNow()
	for _, node := range list {
		if node.Status != 1 {
			continue
		}
		ppe, ok := ppeMap[node.PPEID]
		if !ok {
			j_log.LogWarning([]interface{}{fmt.Sprintf("当前PPE_ID不存在, 忽略当前节点; id=%d, ppe_id=%d, NodeId=%s", node.ID, node.PPEID, node.NodeId)})
			_ = model.DB.Model(&model.OPCNodes{}).Where("id = ?", node.ID).Update("status", 3).Error
			continue
		}

		data := &model.FrameItem{}
		data.ProjectID = node.ProjectID
		data.PPEID = node.PPEID
		data.FieldName = node.NodeId
		data.OPCAddr = node.NodeId
		data.SpecType = "float32"
		data.Code1 = ppe.Code1
		data.Code2 = ppe.Code2
		data.Code3 = ppe.Code3

		frameItemExist := &model.FrameItem{}
		err = model.DB.Where("ppe_id = ? AND opc_addr = ?", node.PPEID, node.NodeId).Limit(1).Find(&frameItemExist).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		if frameItemExist.ID != 0 {
			j_log.LogWarning([]interface{}{fmt.Sprintf("当前OPC设备下的变量地址重复, 忽略当前节点; id=%d, ppe_id=%d, NodeId=%s", node.ID, node.PPEID, node.NodeId)})
			_ = model.DB.Model(&model.OPCNodes{}).Where("id = ?", node.ID).Update("status", 3).Error
			continue
		}
		usedCode4 := make([]string, 0)
		err = model.DB.Model(&model.FrameItem{}).Where("project_id = ? AND code1 = ? AND code2 = ? AND code3 = ?", node.ProjectID, data.Code1, data.Code2, data.Code3).Pluck("code4", &usedCode4).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		availableCode4 := model.GetAvailableCode(model.AllCode4(), usedCode4)
		if len(availableCode4) < 1 {
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "每个OPC设备只支持1000个变量",
			})
			return
		}

		data.Code4 = availableCode4[0]
		data.Addr = fmt.Sprintf("%s-%s-%s-%s", data.Code1, data.Code2, data.Code3, data.Code4)
		data.CreateTime = &now
		data.UpdateTime = &now
		err = model.DB.Create(data).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		_ = model.DB.Model(&model.OPCNodes{}).Where("id = ?", node.ID).Update("status", 2).Error
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con PPEController) CANModelList(ctx *gin.Context) {
	param := struct {
		PPEID int `json:"ppe_id"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	tx := model.DB.Model(&model.CANModel{})
	if param.PPEID != 0 {
		tx.Where("ppe_id = ?", param.PPEID)
	}
	var count int64
	list := make([]*model.CANModel, 0)
	err = tx.Model(&model.CANModel{}).Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = tx.Order("id desc").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

func (con PPEController) CANModelSave(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		ID      int    `json:"id"`
		PPEID   int    `json:"ppe_id" binding:"required"`  // ppe_id
		Content string `json:"content" binding:"required"` // CAN成组数据结构(前端自定义)
	}{}

	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	ppe := &model.PPE{}
	exist, err := ppe.Exists(param.PPEID)
	if !exist {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的 ppe_id",
			"data":    err,
		})
		return
	}
	if ppe.ProtocolName != "CAN2.0B" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "当前设备不是CAN2.0B通讯协议",
		})
		return
	}
	now := tools.GetNow()
	data := &model.CANModel{}
	data.ProjectID = userToken.ProjectID
	data.PPEID = param.PPEID
	data.Content = param.Content
	data.UpdateTime = &now

	if param.ID == 0 {
		data.CreateTime = &now
		err = model.DB.Create(data).Error
	} else {
		err = model.DB.Where("id = ?", param.ID).Select("content", "update_time").Updates(data).Error
	}
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con PPEController) CANModelDelete(ctx *gin.Context) {
	param := struct {
		Id int `json:"id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	info := model.CANModel{}
	err = model.DB.Model(&model.CANModel{}).Where("id = ?", param.Id).First(&info).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = model.DB.Where("id = ?", param.Id).Delete(&model.CANModel{}).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con PPEController) ModbusServerDBSave(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		ID         int    `json:"id"`
		PPEID      int    `json:"ppe_id" binding:"required"`      // ppe_id
		SlaveID    uint8  `json:"slave_id"`                       // slave_id
		JsonDetail string `json:"json_detail" binding:"required"` // 点位绑定关系
		Desc       string `json:"desc" binding:"max=255"`         // 备注, 选填
	}{}

	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数" + err.Error(),
			"data":    map[string]interface{}{},
		})
		return
	}
	ppe := &model.PPE{}
	exist, err := ppe.Exists(param.PPEID)
	if !exist {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的 ppe_id",
			"data":    err,
		})
		return
	}
	if ppe.ProtocolName != "MODBUS TCP" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "当前设备不是MODBUS TCP通讯协议",
		})
		return
	}
	config := &model.ModbusTCPConfig{}
	err = json.Unmarshal([]byte(ppe.Config), config)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "modbus config json解析失败",
			"data":    err.Error(),
		})
		return
	}
	if config.Mode != "server" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "当前设备不是MODBUS TCP服务模式",
		})
		return
	}

	now := tools.GetNow()
	data := &model.ModbusServerDB{}
	data.ProjectID = userToken.ProjectID
	data.PPEID = param.PPEID
	data.SlaveID = param.SlaveID
	data.JsonDetail = param.JsonDetail
	data.Desc = param.Desc
	data.UpdateTime = &now

	pointList, err := model.ValidateModbusPointBind(userToken.ProjectID, param.JsonDetail)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": err.Error(),
			"data":    "",
		})
		return
	}
	jsonB, _ := json.Marshal(pointList)
	data.JsonDetail = string(jsonB)

	if param.ID == 0 {
		data.CreateTime = &now
		slaveExist := &model.ModbusServerDB{}
		err = model.DB.Where("ppe_id = ? AND slave_id = ?", param.PPEID, param.SlaveID).Limit(1).Find(slaveExist).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		if slaveExist.ID != 0 {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "slave_id已存在",
			})
			return
		}
		err = model.DB.Create(data).Error
	} else {
		old := &model.ModbusServerDB{}
		exist, err = old.Exists(param.ID)
		if !exist {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数 id",
				"data":    err,
			})
			return
		}
		slaveExist := &model.ModbusServerDB{}
		err = model.DB.Where("id != ? AND ppe_id = ? AND slave_id = ?", param.ID, param.PPEID, param.SlaveID).Limit(1).Find(slaveExist).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return

		}
		if slaveExist.ID != 0 {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "slave_id已存在",
			})
			return
		}
		err = model.DB.Where("id = ?", param.ID).Select("slave_id", "json_detail", "desc", "update_time").Updates(data).Error
	}

	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

func (con PPEController) ModbusServerDBList(ctx *gin.Context) {
	param := struct {
		PPEID int `json:"ppe_id"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	tx := model.DB.Model(&model.ModbusServerDB{})
	if param.PPEID != 0 {
		tx.Where("ppe_id = ?", param.PPEID)
	}
	var count int64
	list := make([]*model.ModbusServerDB, 0)
	err = tx.Model(&model.ModbusServerDB{}).Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = tx.Order("id ASC").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

func (con PPEController) ModbusServerDBDelete(ctx *gin.Context) {
	param := struct {
		ID int `json:"id"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	old := &model.ModbusServerDB{}
	exist, err := old.Exists(param.ID)
	if !exist {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数id",
			"data":    err,
		})
		return
	}
	err = model.DB.Where("id = ?", param.ID).Delete(&model.ModbusServerDB{}).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}
